package pce

import (
	"fmt"
	"pceservice/internal/pce/strategy"
	"pceservice/internal/topology"
)

// Engine 路径计算引擎
type Engine struct {
	topoManager *topology.Manager
	evaluator   *PathEvaluator
}

// SetPathEvaluator 设置路径评估器
func (e *Engine) SetPathEvaluator(evaluator *PathEvaluator) {
	e.evaluator = evaluator
}

// GetPathEvaluator 获取路径评估器
func (e *Engine) GetPathEvaluator() *PathEvaluator {
	return e.evaluator
}

// CreateDefaultPathEvaluator 创建默认路径评估器
func (e *Engine) CreateDefaultPathEvaluator() {
	e.evaluator = NewPathEvaluator(0.4, 0.2, 0.2, 0.2) // 时延权重最高
}

// CalculateAndEvaluatePath 计算并评估路径
func (e *Engine) CalculateAndEvaluatePath(strategy *strategy.CompositeStrategy, source, destination string) (*strategy.Path, *PathEvaluationResult, error) {
	path, err := e.CalculatePath(strategy, source, destination)
	if err != nil {
		return nil, nil, err
	}

	if e.evaluator == nil {
		e.CreateDefaultPathEvaluator()
	}

	result, err := e.evaluator.Evaluate(path)
	if err != nil {
		return nil, nil, err
	}

	return path, result, nil
}

// CalculateMultiplePaths 计算多条路径（基于不同策略）
func (e *Engine) CalculateMultiplePaths(source, destination string) ([]*strategy.Path, error) {
	// 创建不同的策略
	strategies := []*strategy.CompositeStrategy{
		// 最小时延策略
		strategy.CreateStrategy(strategy.Constraint{Constraints: []strategy.ConstraintType{strategy.MinDelay}}, nil, nil),
		// 最小跳数策略
		strategy.CreateStrategy(strategy.Constraint{Constraints: []strategy.ConstraintType{strategy.MinHop}}, nil, nil),
		// 最小成本策略
		strategy.CreateStrategy(strategy.Constraint{Constraints: []strategy.ConstraintType{strategy.MinCost}}, nil, nil),
		// 带宽均衡策略
		strategy.CreateStrategy(strategy.Constraint{Constraints: []strategy.ConstraintType{strategy.BalancedBandwidth}}, nil, nil),
	}

	// 计算每条策略的路径
	paths := make([]*strategy.Path, 0, len(strategies))
	for _, s := range strategies {
		path, err := e.CalculatePath(s, source, destination)
		if err != nil {
			continue // 跳过计算失败的路径
		}
		paths = append(paths, path)
	}

	if len(paths) == 0 {
		return nil, fmt.Errorf("未能计算出任何路径")
	}

	return paths, nil
}

// CalculateBestPath 计算最佳路径（基于评估器）
func (e *Engine) CalculateBestPath(source, destination string) (*strategy.Path, *PathEvaluationResult, error) {
	paths, err := e.CalculateMultiplePaths(source, destination)
	if err != nil {
		return nil, nil, err
	}

	if e.evaluator == nil {
		e.CreateDefaultPathEvaluator()
	}

	return e.evaluator.GetBestPath(paths)
}

// type Constraint struct {
// 	minHop            string //最小跳数
// 	minDelay          string // 最小时延
// 	balancedBandwidth string // 带宽均衡
// 	minCost           string // 最小cost
// 	mustPass          string // 必须经过某些节点或边
// 	mustNotPass       string // 不得经过某些节点或边
// }

// NewEngine 创建新的路径计算引擎
func NewEngine(topoManager *topology.Manager) *Engine {
	return &Engine{
		topoManager: topoManager,
	}
}

// buildGraph 从拓扑管理器构建图
func (e *Engine) buildGraph() *strategy.Graph {
	graph := &strategy.Graph{Nodes: make(map[string]*strategy.GraphNode)}

	// 添加所有节点
	for _, node := range e.topoManager.GetNodes() {
		graph.Nodes[node.ID] = &strategy.GraphNode{
			ID:        node.ID,
			Adjacents: make(map[string]*strategy.LinkWithAttrs),
		}
	}

	// 添加所有链路
	for _, link := range e.topoManager.GetLinks() {
		srcNode := graph.Nodes[link.SourceNodeID]
		dstNode := graph.Nodes[link.DestinationNodeID]

		if srcNode != nil && dstNode != nil {
			// 构建带属性的链路
			linkAttrs := &strategy.LinkWithAttrs{
				LinkID:      link.ID,
				SourceNode:  link.SourceNodeID,
				DestNode:    link.DestinationNodeID,
				Bandwidth:   link.Bandwidth,
				Delay:       link.Delay,
				Metric:      link.Metric,
				Utilization: 0.0, // 可根据实际流量计算
			}

			// 添加邻接关系（有向图）
			srcNode.Adjacents[dstNode.ID] = linkAttrs
		}
	}

	return graph
}

// todo 需要封装 stargegy的CreateStrategy和CalculatePath，保持 PCE 内部数据模型的独立性
// CreateStrategy 封装 strategy 包的 CreateStrategy 函数
func (e *Engine) CreateStrategy(constraint strategy.Constraint, mustPassCfg *strategy.MustPassConfig, notPassCfg *strategy.MustNotPassConfig) *strategy.CompositeStrategy {
	return strategy.CreateStrategy(constraint, mustPassCfg, notPassCfg)
}

// CalculatePath 封装 strategy 包的 CalculatePath 函数
func (e *Engine) CalculatePath(strategy *strategy.CompositeStrategy, source, destination string) (*strategy.Path, error) {
	graph := e.buildGraph()
	return strategy.CalculatePath(graph, source, destination)
}
